﻿namespace MicroCloud.Authorization
{
    /// <summary>
    /// 实体信息基类
    /// </summary>
    [DebuggerDisplay("{ToString()}")]
    [EventEntityIgnore]
    [ValueGenerate(ValueGenerateRule.Never, ValueGenerateMode.Snowflake)]
    public abstract class EntityInfoBase : EntityBase<long>, IEntityInfo, ICreatedTime, IUpdatedTime, IDataVersion
    {
        #region 属性
        #region 获取或设置 实体名称
        private string _Name = "";
        /// <summary>
        /// 获取或设置 实体名称
        /// </summary>
        [Column("Name")]
        [Required, DefaultValue("")]
        [StringSize(StringSizeType.Name)]
        [DisplayName("实体名称")]
        public string Name { get { return _Name; } set { _Name = value.ReplaceNull(); } }
        #endregion

        #region "获取或设置 实体类型名称"
        private string _TypeName = "";
        /// <summary>
        /// 获取或设置 实体类型名称
        /// </summary>
        [Column("TypeName")]
        [Required, DefaultValue("")]
        [StringSize(StringSizeType.General)]
        [DisplayName("实体类型名称")]
        public string TypeName { get { return _TypeName; } set { _TypeName = value.ReplaceNull(); } }
        #endregion

        #region "获取或设置 数据库架构"
        private string _DbSchema = "";
        /// <summary>
        /// 获取或设置 数据库架构
        /// </summary>
        [Column("DbSchema")]
        [Required, DefaultValue("")]
        [StringSize(StringSizeType.Code)]
        [DisplayName("数据库架构")]
        public string DbSchema { get { return _DbSchema; } set { _DbSchema = value.ReplaceNull(); } }
        #endregion

        #region "获取或设置 数据库对象名称"
        private string _DbObjName = "";
        /// <summary>
        /// 获取或设置 数据库对象名称
        /// </summary>
        [Column("DbObjName")]
        [Required, DefaultValue("")]
        [StringSize(StringSizeType.Code)]
        [DisplayName("数据库对象名称")]
        public string DbObjName { get { return _DbObjName; } set { _DbObjName = value.ReplaceNull(); } }
        #endregion

        #region "获取或设置 数据库对象类型"
        /// <summary>
        /// 获取或设置 数据库对象类型
        /// </summary>
        [Column("DbObjType")]
        [DisplayName("数据库对象类型")]
        public DatabaseObjectType DbObjType { get; set; }
        #endregion

        #region "获取或设置 是否启用数据审计"
        /// <summary>
        /// 获取或设置 是否启用数据审计
        /// </summary>
        [Column("AuditEnabled")]
        [DisplayName(" 启用数据审计")]
        public bool AuditEnabled { get; set; } = true;
        #endregion

        #region "获取或设置 是否启用数据事件"
        /// <summary>
        /// 获取或设置 是否启用数据事件
        /// </summary>
        [Column("EventEnabled")]
        [DisplayName("启用数据事件")]
        public bool EventEnabled { get; set; } = true;
        #endregion

        #region "获取或设置 实体属性信息JSON字符串"
        private string _PropertyJson = "";
        /// <summary>
        /// 获取或设置 实体属性信息JSON字符串
        /// </summary>
        [Column("PropertyJson")]
        [StringMax]
        [DisplayName("实体属性信息Json字符串")]
        public string PropertyJson { get { return _PropertyJson; } set { _PropertyJson = value.ReplaceNull(); } }
        #endregion

        #region "获取或设置 创建时间 ICreatedTime、ICreationAudited  可装载接口，在数据创建时可自动设置当前时间"
        /// <summary>
        /// 获取或设置 创建时间
        /// </summary>
        [Column("CreatedTime")]
        [DisplayName("创建时间")]
        public DateTime CreatedTime { get; set; }
        #endregion

        #region "获取或设置 更新时间 IUpdatedTime、IUpdateAudited 可装载接口，在数据更新时可自动设置当前时间"
        /// <summary>
        /// 获取或设置 更新时间
        /// </summary>
        [Column("UpdatedTime")]
        [DisplayName("更新时间")]
        public DateTime? UpdatedTime { get; set; }
        #endregion

        #region "获取或设置 数据版本 IDataVersion 可装载接口，用于乐观并发处理"
        /// <summary>
        /// 获取或设置 数据版本
        /// 在实体提交验证后（增加、修改）会自动设置一个时间戳值持久化至数据库
        /// 修改、移除时取实体数据库值与提交值比对，如不一致则拒绝提交
        /// </summary>
        [AuditIgnore]
        [Column("DataVersion")]
        [DisplayName("数据版本")]
        public long DataVersion { get; set; }
        #endregion

        #region "获取 实体属性信息"
        /// <summary>
        /// 获取 实体属性信息
        /// </summary>
        [NotMapped]
        [DisplayName("实体属性信息")]
        public EntityProperty[] Properties
        {
            get
            {
                if (string.IsNullOrEmpty(PropertyJson) || !PropertyJson.StartsWith("["))
                {
                    return Array.Empty<EntityProperty>();
                }

                return PropertyJson.FromJsonString<EntityProperty[]>();
            }
        }
        #endregion

        #endregion

        #region "方法"
        #region "从实体类型初始化实体信息"
        /// <summary>
        /// 从实体类型初始化实体信息
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="serviceProvider"></param>
        public virtual void FromType(Type entityType, IServiceProvider serviceProvider)
        {
            Check.NotNull(entityType, nameof(entityType));

            Name = entityType.GetDescription();
            TypeName = entityType.GetFullNameWithModule();

            AuditEnabled = true;
            EventEnabled = true;

            // 执行<see cref="ServiceLifetime.Scoped"/>生命周期的业务逻辑
            serviceProvider.ExecuteScopedWork(provider =>
            {
                IUnitOfWork unitOfWork = provider.GetUnitOfWork();
                var dbContext = unitOfWork.GetEntityDbContext(entityType);
                // 存在数据库视图属性，取视图架构和名称，否则取表架构和名称
                if (entityType.HasAttribute<DatabaseViewAttribute>())
                {
                    DbSchema = dbContext.GetViewSchema(entityType);
                    DbObjName = dbContext.GetViewName(entityType);
                    DbObjType = DatabaseObjectType.View;
                }
                else
                {
                    DbSchema = dbContext.GetTableSchema(entityType);
                    DbObjName = dbContext.GetTableName(entityType);
                    DbObjType = DatabaseObjectType.Table;
                }
            });

            PropertyInfo[] propertyInfos = entityType.GetProperties(BindingFlags.Instance | BindingFlags.Public);

            Dictionary<string, EntityPropertyFlag> entityPropertyFlags = new();
            if (entityType.IsBaseOn(typeof(ICreationAudited<>)) || entityType.IsBaseOn(typeof(ICreationAudited)))
            {
                entityPropertyFlags.Add("CreatorId", EntityPropertyFlag.UserFlag);
            }
            if (entityType.IsBaseOn(typeof(IUpdateAudited<>)) || entityType.IsBaseOn(typeof(IUpdateAudited)))
            {
                entityPropertyFlags.Add("UpdaterId", EntityPropertyFlag.UserFlag);
            }
            if (entityType.IsBaseOn(typeof(IOrganizationAudited<>)) || entityType.IsBaseOn(typeof(IOrganizationAudited)))
            {
                entityPropertyFlags.Add("OrganizationId", EntityPropertyFlag.OrganizationFlag);
            }
            if (entityType.IsBaseOn(typeof(IDepartmentAudited<>)) || entityType.IsBaseOn(typeof(IDepartmentAudited)))
            {
                entityPropertyFlags.Add("DepartmentId", EntityPropertyFlag.DepartmentFlag);
            }

            string[] exceptNames = { "DeletedTime" };
            string[] ignoreNames = { "Id" };
            PropertyJson = propertyInfos.Where(m => !exceptNames.Contains(m.Name) && !m.HasAttribute<NotMappedAttribute>() && (!m.IsVirtual() || ignoreNames.Contains(m.Name))).Select(property =>
            {
                EntityProperty ep = new()
                {
                    Name = property.Name,
                    Display = property.GetDescription(),
                    TypeName = property.PropertyType.FullName
                };
                //枚举类型，获取枚举项作为取值范围
                if (property.PropertyType.IsEnum)
                {
                    ep.TypeName = typeof(int).FullName;
                    Type enumType = property.PropertyType;
                    Array values = enumType.GetEnumValues();
                    int[] intValues = values.Cast<int>().ToArray();
                    string[] names = values.Cast<Enum>().Select(m => m.ToDescription()).ToArray();
                    for (int i = 0; i < intValues.Length; i++)
                    {
                        string value = intValues[i].ToString();
                        ep.ValueRange.Add(new { id = value, text = names[i] });
                    }
                }

                //设置属性标志
                var entityPropertyFlag = entityPropertyFlags.FirstOrDefault(o => o.Key.ToLower() == property.Name.ToLower());
                if (property.HasAttribute<UserFlagAttribute>() || entityPropertyFlag.Value == EntityPropertyFlag.UserFlag)
                {
                    ep.Flags.Add(EntityPropertyFlag.UserFlag);
                }
                if (property.HasAttribute<OrganizationFlagAttribute>() || entityPropertyFlag.Value == EntityPropertyFlag.OrganizationFlag)
                {
                    ep.Flags.Add(EntityPropertyFlag.OrganizationFlag);
                }
                if (property.HasAttribute<DepartmentFlagAttribute>() || entityPropertyFlag.Value == EntityPropertyFlag.DepartmentFlag)
                {
                    ep.Flags.Add(EntityPropertyFlag.DepartmentFlag);
                }

                return ep;
            }).ToArray().ToJsonString();
        }
        #endregion
        #region "返回一个表示当前对象的String"
        /// <summary>
        /// 返回一个表示当前对象的String
        /// </summary>
        /// <returns>表示当前对象的字符串</returns>
        public override string ToString()
        {
            return $"{Name}[{TypeName}]";
        }
        #endregion

        #endregion

    }

}
